#ifndef _M_FORMATTER_H
#define _M_FORMATTER_H
#include "util.hpp"
#include "level.hpp"
#include "log_msg_set.hpp"
#include <memory>
#include <cassert>
#include <vector>
#include <sstream>
class Formatitem
{

public:
    using fptr = std::shared_ptr<Formatitem>;
    Formatitem(const std::string &str = "") {}
    virtual void Format(std::ostream &out, const Logmsg &msg) = 0;
};

class MsgFormatitem : public Formatitem
{
public:
    MsgFormatitem(const std::string &str = "") {}

    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << msg._payload;
    }
};

class LevelFormatitem : public Formatitem
{
public:
    LevelFormatitem(const std::string &str = "") {}

    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << Level::Tostring(msg._level);
    }
};

class TimeFormatitem : public Formatitem
{

private:
    std::string _format;

public:
    TimeFormatitem(const std::string &format = "%H:%M:%S") : _format(format)
    {
        if (format.empty())
        {
            _format = "%H:%M:%S";
        }
    }

    void Format(std::ostream &out, const Logmsg &msg) override
    {
        time_t t = msg._ctime;
        struct tm *local = localtime(&t);
        char buf[128] = {0};
        strftime(buf, 128, _format.c_str(), local);
        out << buf;
    }
};

class FileFormatitem : public Formatitem
{
public:
    FileFormatitem(const std::string &str = "") {}
    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << msg._file;
    }
};

class LineFormatitem : public Formatitem
{
public:
    LineFormatitem(const std::string &str = "") {}
    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << msg._line;
    }
};

class LoggernameFormatitem : public Formatitem
{
public:
    LoggernameFormatitem(const std::string &str = "") {}
    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << msg._name;
    }
};

class ThreadFormatitem : public Formatitem
{
public:
    ThreadFormatitem(const std::string &str = "") {}
    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << msg._tid;
    }
};

class TableFormatitem : public Formatitem
{
public:
    TableFormatitem(const std::string &str = "") {}

    void Format(std::ostream &out, const Logmsg &msg)
    {

        out << "\t";
    }
};

class ClineFormatitem : public Formatitem
{
public:
    ClineFormatitem(const std::string &str = "") {}
    void Format(std::ostream &out, const Logmsg &msg)
    {
        out << "\n";
    }
};

class OtherFormatitem : public Formatitem
{
private:
    std::string _str;

public:
    OtherFormatitem(const std::string &str = "") : _str(str) {}
    void Format(std::ostream &out, const Logmsg &msg) override
    {
        out << _str;
    }
};

class Formatter
{

public:
     using fptr=std::shared_ptr<Formatter>;
    Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n") : _pattern(pattern)
    {
        assert(Parsepattern());
    }

    void Format(std::ostream &ot, const Logmsg msg)
    {

        for (auto &it : _items)
        {
            it->Format(ot, msg);
        }
    }

    std::string Format(const Logmsg msg)
    {
        std::stringstream ss;
        for (auto &it : _items)
        {
            it->Format(ss, msg);
        }
        return ss.str();
    }

private:
    // sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n
    // 解析到_item里面（按顺序填充需要打印的内容）：
    bool Parsepattern()
    {
        // 1.完成字符串的转义对应工作:
        //abc%%abc[%d{%H:%M:%S}] %m%n
        std::string key, val;
        size_t pos = 0;
        while (pos < _pattern.size())
        {
            if (_pattern[pos] != '%')
            {
                val.push_back(_pattern[pos++]);
                continue;
            }
            // 说明当前位置就是%：
            if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
            {
                val.push_back('%');
                pos += 2;
                continue;
            }
            // 把对应无需转义的放进数组：
            _transarr.push_back({key, val});
            key.clear();
            val.clear();
            // 说明下一个是需要转义的字符
            pos += 1;
            if (pos >= _pattern.size())
            {
                std::cout << "%匹配失败，意外退出" << std::endl;
                return false;
            }
            key = _pattern[pos++]; //++后pos位置要么是{ 要么是转义字符的下一个位置
            // 检测是不是日期转义的那个：
            if (pos < _pattern.size() && _pattern[pos] == '{')
            {
                // 作为日期d的val进行添加：
                pos += 1;
                while (pos < _pattern.size() && _pattern[pos] != '}')
                {
                    val.push_back(_pattern[pos++]);
                }
                // 说明要么越界退出（无}）要么找到了}
                if (pos >= _pattern.size())
                {
                    std::cout << "{}匹配失败，意外退出" << std::endl;
                    return false;
                }
                // 说明正常退出：
                  pos += 1;//这里需要跳过这个}
               
            }
             
            _transarr.push_back({key, val});
            key.clear();
            val.clear();
        }
        // 2· 遍历对应关系完善对应item：

        for (auto &it : _transarr)
        {
            _items.push_back(Createitem(it.first, it.second));
        }
        return 1;
    }

    // 对应的进行解析匹配工作：
    // 1`如果是原字符串也就是key为null而val为实际原字符串不需要转移直接输出（调other的子项）
    // 2·如果是对应的转移字母就需要进行匹配工作
    Formatitem::fptr Createitem(const std::string &key, const std::string &val)
    {

        if (key == "m")
            return Formatitem::fptr(new MsgFormatitem());
        if (key == "p")
            return Formatitem::fptr(new LevelFormatitem());
        if (key == "c")
            return Formatitem::fptr(new LoggernameFormatitem());
        if (key == "t")
            return Formatitem::fptr(new ThreadFormatitem());
        if (key == "n")
            return Formatitem::fptr(new ClineFormatitem());
        if (key == "d")
            return Formatitem::fptr(new TimeFormatitem(val));
        if (key == "f")
            return Formatitem::fptr(new FileFormatitem());
        if (key == "l")
            return Formatitem::fptr(new LineFormatitem());
        if (key == "T")
            return Formatitem::fptr(new TableFormatitem());
        if (key.empty())
        {
            return Formatitem::fptr(new OtherFormatitem(val));
            std::cout << ":" << val << std::endl;
        }
        std::cout << "没有对应的格式化字符:%" << key << std::endl;
        abort();
        return Formatitem::fptr();
    }

private:
    std::string _pattern;
    std::vector<Formatitem::fptr> _items;
    std::vector<std::pair<std::string, std::string>> _transarr;
};

#endif